package com.yuandian.business.monitor.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.BeanUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yuandian.api.business_monitor.po.AdvancedQuery;
import com.yuandian.api.business_monitor.po.DetailedListParams;
import com.yuandian.api.business_monitor.po.SearchParams;
import com.yuandian.api.business_monitor.vo.BusinessDetailedListVO;
import com.yuandian.api.business_monitor.vo.CodeDetailsVo;
import com.yuandian.api.management.entity.ConfReturnCode;
import com.yuandian.api.management.feign.RemoteAlarmIndicatorsService;
import com.yuandian.api.management.feign.RemoteExclusiveIndicatorService;
import com.yuandian.api.management.feign.RemoteReturnCodeService;
import com.yuandian.bpm.common.core.constant.SecurityConstants;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.business.monitor.mapper.BusinessDetailMapper;
import com.yuandian.business.monitor.service.IBusinessDetailedListService;
import com.yuandian.constant.Constants;
import com.yuandian.enums.BaseTableName;
import com.yuandian.po.DocumentExportApplicationForm;
import com.yuandian.utils.*;
import com.yuandian.utils.poi.ExcelTitleUtils;
import com.yuandian.utils.poi.ExcelUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 详单查询
 *
 * @author zhoutian
 * @date 2020/10/13 16:15
 */
@Slf4j
@Service
public class BusinessDetailedListServiceImpl implements IBusinessDetailedListService {

//    @Autowired
//    private ISearchOptionService searchOptionService;
    @Autowired
	BusinessDetailMapper businessDetailMapper;

//    @Autowired
//    private TableShardingService tableShardingService;
    private String[] completionState = new String[]{"不完整", "完整"};
    private String[] dealState = new String[]{"失败", "成功"};
	@Autowired
	private RemoteAlarmIndicatorsService remoteAlarmIndicatorsService;
	@Autowired
	private RemoteReturnCodeService remoteReturnCodeService;
	@Autowired
	private ExclusiveIndicator exclusiveIndicator;
	@Autowired
	private RemoteExclusiveIndicatorService remoteExclusiveIndicatorService;

//    private static TransportClient bpmClient = null;

//    @Autowired
//    ElasticsearchClientPool elasticsearchClientPool;

//    @Autowired
//    private DocumentExportController exportController;

    /**
     * 详单查询列表查询
     *
     * @param params 参数
     * @return PageDataInfo
     */
    @Override
    public PageDataInfo queryList(DetailedListParams params) {


        if (StringUtils.isEmpty(params.getOrderByColumn())) {
            params.setIsAsc("desc");
            params.setOrderByColumn("end_time_usec");
        }
        IPage<BusinessDetailedListVO> page = new Page<>(params.getPageNum(), params.getPageSize());
        List<AdvancedQuery> advancedQuery = params.getAdvancedQuery();
        //将列名转换成下划线命名
        if (advancedQuery != null){
            advancedQuery.forEach(e -> e.setColumn(StringUtils.toUnderlineName(e.getColumn())));
            params.setAdvancedQuery(advancedQuery);
        }

		// 判断查询 定性详单表(dws_business_detail) 还是 未定性的详单表(dws_business_detail_unsure)
		params.setTableName(params.getIsUnsure() == 0 ? BaseTableName.BUSINESS_DETAIL.getName() : BaseTableName.BUSINESS_DETAIL_UNSURE.getName());


        List<BusinessDetailedListVO> list = businessDetailMapper.queryList(page, params);

        // 获取 自定义返回码注释 回填到前端
        Map<String, String> codeMap = getCodeExplain();
        String explain = "";
        List<Map<String, Object>> resList = new ArrayList<>();
        LinkedHashMap<String, Object> customMap = exclusiveIndicator.getCustomMap();
		if(ObjectUtil.isNotEmpty(list)){
			Map<String, List<String>> businessIndicatorsShowMap = remoteExclusiveIndicatorService.getBusinessIndicatorsShowMap().getData();
			// 组装数据
			for (BusinessDetailedListVO businessDetailedListVO : list) {
				//根据配置处理专属指标是否显示
				String exclusiveIndicator = businessDetailedListVO.getExclusiveIndicator();
				businessDetailedListVO.setExclusiveIndicator(ExclusiveIndicator.getIndicatorWithSet(exclusiveIndicator, businessIndicatorsShowMap.get(businessDetailedListVO.getBusinessCode())));

				Map<String, Object> map = BeanUtil.beanToMap(businessDetailedListVO);
				String indexId = businessDetailedListVO.getId();
				explain = codeMap.get(map.get("systemName") + "@" + map.get("customResCode"));

				map.put("completionState", completionState[Convert.toInt(map.get("completionState"))]);
				map.put("dealState", dealState[Convert.toInt(map.get("dealState"))]);//完整不完整
				map.put("dealTime", YDateUtil.getMinSecond(Double.parseDouble(map.get("dealTime").toString()) / 1000));
				map.put("clientFreeTime", YDateUtil.getMinSecond(Double.parseDouble(map.get("clientFreeTime").toString()) / 1000));
				map.put("explain", explain);
				map.put("id", indexId);

				// 对专属指标进行切割
				ExclusiveIndicator.getValueFromSpecifyParameters(map, customMap);
				resList.add(map);
			}
		}
        return new PageDataInfo(page.getTotal(), resList);
    }

    /**
     * 详单查询获取要查询的字段
     *
     * @return
     */
    private String[] getFields() {

        String[] fields = {
                "systemName", "businessName", "userIdentify", "startTime", "endTime", "startTimeUsec", "endTimeUsec",
                "dealState", "completionState", "dealTime", "customResCode", "alarmCount", "clientFreeTime", "exclusiveIndicator"
        };
        return fields;
    }

    public Map<String, String> getCodeExplain() {

        Map<String, String> resMap = new HashMap<>();
        SearchParams params = new SearchParams();
        // 4:自定返回码类型  3: 数据库返回码 2：中间件返回码  1：web 返回码
		ConfReturnCode confReturnCode = new ConfReturnCode();
		confReturnCode.setTypeId(4);
		List<ConfReturnCode> list = remoteReturnCodeService.getCodeDetail(confReturnCode).getData();
		if (list != null && list.size() > 0) {
            resMap = list.stream().collect(Collectors.toMap(ConfReturnCode::getNameAndValue, ConfReturnCode::getExplain, (key1, key2) -> key2));
        }
        return resMap;
    }



    // 异步下载会调用此方法
    public void exportExcel(DocumentExportApplicationForm documentExportApplicationForm) {
        DetailedListParams params = null;
        try {
            params = new ObjectMapper().readValue(documentExportApplicationForm.getDocExportParameterJson(), DetailedListParams.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (StringUtils.isEmpty(params.getOrderByColumn())) {
            params.setIsAsc("desc");
            params.setOrderByColumn("end_time_usec");
        } else {
            params.setOrderByColumn(StringUtils.toUnderlineName(params.getOrderByColumn()));
        }
        List<AdvancedQuery> advancedQuery = params.getAdvancedQuery();
        //将列名转换成下划线命名
        if(advancedQuery != null &&advancedQuery.size() >0){
            advancedQuery.forEach(e -> e.setColumn(StringUtils.toUnderlineName(e.getColumn())));
            params.setAdvancedQuery(advancedQuery);
        }

        // 设置Excel 信息
        String title = "业务详单列表";
        List<String> titleParams = new ArrayList<>();
        titleParams.add(title);
        titleParams.add(params.getSystemName());
        String formTitleName = ExcelTitleUtils.formTitleName(titleParams, params.getStartTime(), params.getEndTime());
        //需要展示的字段
        List<String> displayFields = new ArrayList<>();
        displayFields.add("序号");
        displayFields.addAll(params.getDisplayFields());
        List<List<String>> headList = new ArrayList<>();
        if (params.getAlarmTypeId() != null) {
			titleParams.add(remoteAlarmIndicatorsService.queryById(params.getAlarmTypeId()).getData().getName());
        }
        displayFields.forEach(s -> {
            List<String> childHeadList = new ArrayList<>();
            childHeadList.add(formTitleName);
            childHeadList.add(s);
            headList.add(childHeadList);
        });

        ExcelWriter excelWriter = null;
        OutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(documentExportApplicationForm.getExportFileName());
            excelWriter = EasyExcel.write(outputStream).build();

//            log.info("查询" + String.join(",", queryTableNames) + "表  request : " + requestBuilder.toString());
//            SearchResponse searchResponse = requestBuilder.get();
            long total = 0;
            // 初始化序号
            int index = 1, sheetIndex = 0, writeNum = 0;
            int pageNum = 1, pageSize = 5000;
            // 获取 自定义返回码注释 回填到前端
            Map<String, String> codeMap = getCodeExplain();

            List<List<Object>> excelList = new ArrayList<>();
            LinkedHashMap<String, Object> customMap = exclusiveIndicator.getCustomMap();
            IPage page = new Page(pageNum, pageSize);
            //创建第一个sheet页
            WriteSheet writeSheet = EasyExcel.writerSheet(sheetIndex, title + (++sheetIndex))
                    .registerWriteHandler(ExcelUtil.defaultStyle)
                    .head(headList)
                    .registerWriteHandler(new SimpleColumnWidthStyleStrategy(20))
                    .registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 30, (short) 20))
                    .build();
            while (true) {
                log.info("开始查询第" + pageNum + "页数据");
                List<BusinessDetailedListVO> list = businessDetailMapper.queryList(page, params);
                total = page.getTotal();
                page.setCurrent(++pageNum);
				if(ObjectUtil.isNotEmpty(list)){
					Map<String, List<String>> businessIndicatorsShowMap = remoteExclusiveIndicatorService.getBusinessIndicatorsShowMap().getData();
					for (BusinessDetailedListVO businessDetailedListVO : list) {
						//根据配置处理专属指标是否显示
						String exclusiveIndicator = businessDetailedListVO.getExclusiveIndicator();
						businessDetailedListVO.setExclusiveIndicator(ExclusiveIndicator.getIndicatorWithSet(exclusiveIndicator, businessIndicatorsShowMap.get(businessDetailedListVO.getBusinessCode())));
						// 把数据封装成横向 List
						List<Object> rowListByHit = getRowListByHit(businessDetailedListVO, codeMap, params.getDisplayMappingFields(), index, customMap);
						index++;
						excelList.add(rowListByHit);
					}
				}
                //如果行数超过60000另起一页
                if (index >= Constants.SHEET_MAX_ROW * sheetIndex) {
                    int tempIndex = Constants.SHEET_MAX_ROW * sheetIndex - writeNum;
                    List<List<Object>> preLists = excelList.subList(0, tempIndex);
                    excelWriter.write(preLists, writeSheet);
                    // 每次都要创建writeSheet 这里必须指定sheetNo 而且sheetName必须不一样
                    writeSheet = EasyExcel.writerSheet(sheetIndex, title + (++sheetIndex))
                            .registerWriteHandler(ExcelUtil.defaultStyle)
                            .head(headList)
                            .registerWriteHandler(new SimpleColumnWidthStyleStrategy(20))
                            .registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 30, (short) 20))
                            .build();
                    List<List<Object>> sufLists = excelList.subList(tempIndex, excelList.size() - 1);
                    excelWriter.write(sufLists, writeSheet);
                }
                excelWriter.write(excelList, writeSheet);
                writeNum = index;
                if (pageNum > page.getPages() || page.getTotal() == 0) {
                    log.info("共导出数据：{}条，当前页数：{}", index, pageNum);
                    break;
                }
                //清空数据
                excelList.clear();
            }
//            ExcelUtil.writeExcel("", response);
        } catch (Exception e) {
            log.error("下载详单查询列表出错！");
            throw new RuntimeException("下载详单查询列表出错! " + e);
        } finally {
            if (excelWriter != null) {
                try {
//                    response.getOutputStream().flush();
                    outputStream.flush();
                    excelWriter.finish();
//                    response.getOutputStream().close();
                    outputStream.close();
                } catch (Exception e) {
                    log.error("IO流关闭异常： " + e.getMessage());
                    throw new RuntimeException("IO流关闭异常： " + e.getMessage());
                }
            }
        }
    }

    /**
     * 组装数据成 List(把单行数据组成横向的List)
     *
     * @param businessDetailedListVO
     * @param codeMap
     * @param displayMappingFields
     * @param excelId
     * @return
     */
    private List<Object> getRowListByHit(BusinessDetailedListVO businessDetailedListVO,
                                         Map<String, String> codeMap,
                                         List<String> displayMappingFields,
                                         int excelId,
                                         LinkedHashMap<String, Object> customMap) {

//        Map<String, Object> map = searchHit.getSourceAsMap();
        Map<String, Object> map = BeanUtils.beanToMap(businessDetailedListVO);
        // 从后台配置获取需要从专属指标提取的字段并从专属指标中提取该字段对应的值
        LinkedHashMap<String, Object> customIndicatorMap = new LinkedHashMap<>();
//		todo ExclusiveIndicator.getValueFromSpecifyParameters(customMap, map.get("exclusiveIndicator") + "");
        if (customIndicatorMap == null) {
            customIndicatorMap = new LinkedHashMap<>();
        }

        // 保存行数据的横向List
        List<Object> rowList = new ArrayList<>();
        rowList.add(excelId);

        String explain = "";
        if (ListUtils.isNotNull(displayMappingFields)) {
            for (String field : displayMappingFields) {
                Object value = map.get(field);
                // 对字段进行特殊处理
                if ("completionState".equals(field)) {
                    value = completionState[Convert.toInt(map.get("completionState"))];
                } else if ("dealState".equals(field)) {
                    value = dealState[Convert.toInt(map.get("dealState"))];
                } else if ("dealTime".equals(field)) {
                    value = YDateUtil.getMinSecond(Double.parseDouble(map.get("dealTime").toString()) / 1000);
                } else if ("clientFreeTime".equals(field)) {
                    value = YDateUtil.getMinSecond(Double.parseDouble(map.get("clientFreeTime").toString()) / 1000);
                } else if ("customResCode".equals(field)) {
                    explain = codeMap.get(map.get("systemName") + "@" + map.get("customResCode"));
                    explain = StringUtils.isEmpty(explain) ? "" : (" (" + explain + ")");
                    value = map.get("customResCode") + explain;
                } else if (!"exclusiveIndicator".equals(field) && customIndicatorMap.get(field) != null) {
                    value = customIndicatorMap.get(field);
                }

                rowList.add(value);
            }
        }
        return rowList;
    }


    /**
     * 不需要展示的字段
     *
     * @param businessDetailedListVOFields
     * @param displayFields
     * @return
     */
    private List<String> getExcludeColumnFields(HashMap<String, String> businessDetailedListVOFields, List<String> displayFields) {
        List<String> excludeColumnFields = new ArrayList<>();
        for (Map.Entry<String, String> stringStringEntry : businessDetailedListVOFields.entrySet()) {
            if (!displayFields.contains(stringStringEntry.getKey())) {
                excludeColumnFields.add(stringStringEntry.getValue());
            }
        }

        return excludeColumnFields;
    }

}
